package com.sias.aopchain;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author 吴文杰
 * @version 1.0
 * @since 2023/6/18 21:34
 */
public class A18_1 {


  public static void main(String[] args) throws Throwable {
    Target target = new Target();
    List<MethodInterceptor> list = Arrays.asList(new Advice1(), new Advice2());
    MyInvocation foo = new MyInvocation(target, list, Target.class.getMethod("foo"), new Object[0]);
    foo.proceed();
  }

  static class Target {
    public void foo() {
      System.out.println("target.foo()");
    }
  }

  static class Advice1 implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

      System.out.println("advice1.before()");
      Object result = invocation.proceed();// 调用下一个通知或目标
      System.out.println("advice1.after()");

      return result;
    }
  }

  static class Advice2 implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

      System.out.println("advice2.before()");
      Object result = invocation.proceed();// 调用下一个通知或目标
      System.out.println("advice2.after()");

      return result;
    }
  }

  static class MyInvocation implements MethodInvocation {

    List<MethodInterceptor> methodInterceptorList;
    private Object target;
    private Method method;
    private Object[] args;
    private int count = 1;

    public MyInvocation(Object target, List<MethodInterceptor> methodInterceptorList, Method method, Object[] args) {
      this.target = target;
      this.methodInterceptorList = methodInterceptorList;
      this.method = method;
      this.args = args;
    }

    @Override
    public Method getMethod() {
      return method;
    }

    @Override
    public Object[] getArguments() {
      return args;
    }

    @Override
    public Object proceed() throws Throwable {
      if (count > methodInterceptorList.size()) {
        return method.invoke(target, args);
      }
      MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);
      return methodInterceptor.invoke(this);
    }

    @Override
    public Object getThis() {
      return target;
    }

    @Override
    public AccessibleObject getStaticPart() {
      return method;
    }
  }
}
